// LCD_Driver.v
/*
LCD1602 LCD1602_u(
		  .Data_First(dis_data1_w),
        .Data_Second(dis_data2_w),
        .clk_LCD(LCD_clk_w),
        .rst(rst_n),
        .LCD_EN(LCD_EN),
        .RS(RS),
        .RW(RW),
        .DB8(DB8),
        .LCD_ON(LCD_ON),
        .LCD_BLON(LCD_BLON));
LCD_clk LCD_clk_u(
        .clk50M(clk),
        .rst_n(rst_n),
        .LCD_clk(LCD_clk_w));
*/


module LCD1602(Data_First,Data_Second,clk_LCD,rst,LCD_EN,RS,RW,DB8,LCD_ON,LCD_BLON);

input   clk_LCD,rst;        //rst为全局复位信号（高电平有效）
input   [127:0] Data_First,Data_Second;

output  LCD_EN,RS,RW,LCD_ON,LCD_BLON;

//LCD_EN为LCD模块的使能信号（下降沿触发）
//RS=0时为写指令；RS=1时为写数据
//RW=0时对LCD模块执行写操作；RW=1时对LCD模块执行读操作

output  [7:0] DB8;          //8位指令或数据总线

//reg   [23:0] Data_First;
reg     [7:0] DB8;
reg     [127:0] Data_First_Buf;     //液晶显示的数据缓存
reg     [127:0] Data_Second_Buf;
reg     RS,LCD_EN_Sel;
reg     [4:0] disp_count;
reg     [3:0] state;
reg      flag;
reg     [9:0] count;
//reg     [7:0] count_clr;
reg LCD_ON_reg;
reg LCD_BLON_reg;
parameter   Clear_Lcd = 4'b0000,                            //清屏并光标复位
            Set_Disp_Mode = 4'b0001,                        //设置显示模式：8位2行5x7点阵   
            Disp_On = 4'b0010,                              //显示器开、光标不显示、光标不允许闪烁
            Shift_Down = 4'b0011,                           //文字不动，光标自动右移
            Write_Addr = 4'b0100,                           //写入显示起始地址
            Write_Data_First = 4'b0101,                     //写入第一行显示的数据
            Write_Data_Second = 4'b0110,                    //写入第二行显示的数据
            Idel = 4'b0111,                                 //空闲状态
            rst_r=4'b1000;

                       


assign  RW = 1'b0;                     //RW=0时对LCD模块执行写操作
assign  LCD_EN = LCD_EN_Sel ? clk_LCD : 1'b0;
assign  LCD_ON = LCD_ON_reg;
assign  LCD_BLON=LCD_BLON_reg;
//通过LCD_EN_Sel信号来控制LCD_EN的开启与关闭

always @(posedge clk_LCD or negedge rst)
begin

   if (!rst)
      begin
          state <= rst_r;                               //复位：清屏并光标复位   
          RS <= 1'b0;                                       //复位：RS=0时为写指令；                       
          DB8 <= 8'b0;                                      //复位：使DB8总线输出全0
          LCD_EN_Sel <= 1'b1;
          LCD_ON_reg<=1'b1;
          LCD_BLON_reg<=1'b0;
          // Data_First<=Data_In;  
         // Data_First<=Data_In;                             //复位：开启夜晶使能信号
          //Data_First_Buf <= Data_First;
          //Data_Second_Buf <= Data_Second;
          disp_count <= 4'b0;
          count<=10'd0;
//          count_clr<=8'd0;
        //  flag<=~flag;
      end
   else 
  //  begin
   //  Data_First<=Data_In;
   //  end;
      case(state)
      rst_r:
        begin
          state <= Clear_Lcd;                               //复位：清屏并光标复位   
          RS <= 1'b0;                                       //复位：RS=0时为写指令；                       
          DB8 <= 8'b0;                                      //复位：使DB8总线输出全0
          LCD_EN_Sel <= 1'b1;
          LCD_ON_reg<=1'b1;
          LCD_BLON_reg<=1'b0;
          // Data_First<=Data_In;  
         // Data_First<=Data_In;                             //复位：开启夜晶使能信号
          //Data_First_Buf <= Data_First;
          //Data_Second_Buf <= Data_Second;
          disp_count <= 4'b0;
          count<=10'd0;
//          count_clr<=8'd0;
        //  flag<=~flag;
      end                                           //初始化LCD模块
      Clear_Lcd:
             begin
                
                state <= Set_Disp_Mode;
                 
                 
                DB8 <= 8'b00000001;                         //清屏并光标复位   
             end
     

      Set_Disp_Mode:
             begin
                state <= Disp_On;
                DB8 <= 8'b00111000;                         //设置显示模式：8位2行5x7点阵         
             end
      Disp_On:
             begin
                state <= Shift_Down;
                DB8 <= 8'b00001100;                         //显示器开、光标不显示、光标不允许闪烁    
             end
      Shift_Down:
            begin
                state <= Write_Addr;
                DB8 <= 8'b00000110;                         //文字不动，光标自动右移    
            end
      Write_Addr:
            begin
                state <= Write_Data_First;
                DB8 <= 8'b10000000;                         //写入第一行显示起始地址：第一行第1个位置    
                Data_First_Buf<=Data_First;               //将第一行显示的数据赋给Data_First_Buf?
                
                
              //  Data_Second_Buf<=Data_Second_Buf;
            end
      Write_Data_First:                                     //写第一行数据
            begin
                if(disp_count == 5'd16)                        //disp_count等于15时表示第一行数据已写完
                    begin
                        DB8 <= 8'b11000000;                 //送入写第二行的指令
                        RS <= 1'b0;
                        disp_count <= 4'b0; 
                        Data_Second_Buf <= Data_Second;
                        state <= Write_Data_Second;         //写完第一行进入写第二行状态
                    end
                else
                    begin
                        DB8 <= Data_First_Buf[127:120];
                        Data_First_Buf <= (Data_First_Buf << 8);
                        RS <= 1'b1;                         //RS=1表示写数据
                        disp_count <= disp_count + 1'b1;
                        state <= Write_Data_First; 
                    end
            end
      Write_Data_Second:                                    //写第二行数据
            begin
                if(disp_count == 5'd16)
                    begin
                        LCD_EN_Sel <= 1'b0;
                        RS <= 1'b0;
                        disp_count <= 4'b0; 
                        state <= Idel;                      
                    end
                else
                    begin
                        DB8 <= Data_Second_Buf[127:120];
                        Data_Second_Buf <= (Data_Second_Buf << 8);
                        RS <= 1'b1;
                        disp_count <= disp_count + 1'b1;
                        state <= Write_Data_Second; 
                    end              
            end
      Idel:
               begin
                if(count==10'd200)
                 begin
                  count<=10'd0;
                  state<=Write_Addr;
                  LCD_EN_Sel <= 1'b1;
                  RS<=1'b0;
                  DB8 <= 8'b10000001;
                 end
                 else
                  begin
                   count<=count+10'd1;
                  end
               end
                
      default:  state <= rst_r;                         //若state为其他值，则将state置为Clear_Lcd 
      endcase 
end

endmodule